1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| diff --git a/sound/soc/rockchip/rockchip_rt5651_tc358749x.c b/sound/soc/rockchip/rockchip_rt5651_tc358749x.c index 21f8ee2..14acebd 100644 --- a/sound/soc/rockchip/rockchip_rt5651_tc358749x.c +++ b/sound/soc/rockchip/rockchip_rt5651_tc358749x.c @@ -18,12 +18,18 @@ #include <linux/module.h> #include <sound/soc.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/clk.h> + #include "rockchip_i2s.h" #include "../codecs/rt5651.h" #include "../codecs/tc358749x.h" #define DRV_NAME "rk3399-rt5651-tc358749x" +#define INVALID_GPIO -1 + static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphones", NULL), SND_SOC_DAPM_SPK("Lineout", NULL), @@ -184,11 +190,58 @@ static struct snd_soc_card rockchip_sound_card = { .num_controls = ARRAY_SIZE(rockchip_controls), }; +static irqreturn_t rt5651_irq_handler(int irq, void *data) +{ + struct snd_soc_card *card = data; + queue_delayed_work(system_power_efficient_wq, &card->work, + msecs_to_jiffies(card->debounce_time)); + + return IRQ_HANDLED; +} + +static void rt5651_enable_spk(struct snd_soc_card *card, bool enable) +{ + bool level; + + level = enable ? card->spk_active_level : !card->spk_active_level; + gpio_set_value(card->spk_ctl_gpio, level); +} + +static void hp_work(struct work_struct *work) +{ + struct snd_soc_card *card; + int enable; + + card = container_of(work, struct snd_soc_card, work.work); + enable = gpio_get_value(card->hp_det_gpio); + if(card->hp_det_invert) + enable = !enable; + + card->hp_inserted = enable ? true : false; + if(card->hp_inserted){ + //printk("hp_work rt5651_enable_spk false\n"); + rt5651_enable_spk(card, false); + } else { + //printk("hp_work rt5651_enable_spk true\n"); + rt5651_enable_spk(card,true); + } +} + static int rockchip_sound_probe(struct platform_device *pdev) { struct snd_soc_card *card = &rockchip_sound_card; struct device_node *cpu_node; - int i, ret; + int i; + int ret = -1; + + int hp_irq; + enum of_gpio_flags flags; + + card->debounce_time = 200; + card->hp_det_invert = 0; + card->hp_inserted = false; + card->spk_ctl_gpio = INVALID_GPIO; + card->hp_det_gpio = INVALID_GPIO; dev_info(&pdev->dev, "%s\n", __func__); @@ -213,6 +266,47 @@ static int rockchip_sound_probe(struct platform_device *pdev) } } + card->spk_ctl_gpio = of_get_named_gpio_flags(pdev->dev.of_node, "spk-con-gpio", 0, &flags); + if(!gpio_is_valid(card->spk_ctl_gpio)) { + dev_err(&pdev->dev,"spk-ctl-gpio: %d is invalid\n", card->spk_ctl_gpio); + card->spk_ctl_gpio = INVALID_GPIO; + }else { + dev_info(&pdev->dev,"spk-ctl-gpio: %d is arrivable\n", card->spk_ctl_gpio); + card->spk_active_level = !(flags & OF_GPIO_ACTIVE_LOW); + ret = devm_gpio_request_one(&pdev->dev, card->spk_ctl_gpio, + GPIOF_DIR_OUT,NULL); + if(ret) { + dev_err(&pdev->dev,"spk_ctl_gpio: request failed!\n"); + } + rt5651_enable_spk(card, true); + } + + card->hp_det_gpio = of_get_named_gpio_flags(pdev->dev.of_node,"hp-det-gpio", 0, &flags); + if(!gpio_is_valid(card->hp_det_gpio)) { + printk("hp-det-gpio: %d is invalid\n",card->hp_det_gpio); + card->hp_det_gpio = INVALID_GPIO; + }else { + INIT_DELAYED_WORK(&card->work, hp_work); + card->hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); + ret = devm_gpio_request_one (&pdev->dev, card->hp_det_gpio,GPIOF_IN,"hp det"); + if( ret < 0) + return ret; + hp_irq = gpio_to_irq(card->hp_det_gpio); + ret = devm_request_threaded_irq(&pdev->dev, hp_irq, NULL, + rt5651_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | + IRQF_ONESHOT, + "rt5651_interrupt", card); + if( ret < 0) { + dev_err(&pdev->dev, "request_irq: failed %d\n", ret); + return ret; + } + + schedule_delayed_work(&card->work, + msecs_to_jiffies(card->debounce_time)); + } + card->dev = &pdev->dev; platform_set_drvdata(pdev, card); ret = devm_snd_soc_register_card(&pdev->dev, card);
|